package com.springapp.mvc.websocket;


import com.springapp.mvc.util.JsonUtils;
import org.apache.http.util.TextUtils;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.socket.server.standard.SpringConfigurator;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * Created by qinyy on 12/10/2018.
 */

/**
 * 加configurator = SpringConfigurator.class是为了让这个类中可以通过注解的方式 注入实例
 * 比如如果不加这个选项的话，那么使用@Autowired 注解引入的实例就是null，无法被spring注入
 */
@ServerEndpoint(value = "/websocket/{id}", configurator = SpringConfigurator.class)
public class WebSocketService
{
    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    // 维护一个map，用来管理不同用户的不同socket实例
    public static HashMap<String,WebSocketService> webSocketMap = new HashMap<String, WebSocketService>();
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    private String currentKey;
    private org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(WebSocketService.class.getSimpleName());

    /**
     * 连接建立成功调用的方法
     * @param session  可选的参数。session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session,@PathParam(value = "id")String id){
        this.session = session;
        webSocketMap.put(id,this); // 加入map中
        currentKey = id;
        addOnlineCount();           //在线数加1
        logger.info("有新连接加入！当前在线人数为" + getOnlineCount());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(){
        if(!TextUtils.isEmpty(currentKey))
            webSocketMap.remove(currentKey);
        subOnlineCount();           //在线数减1
        logger.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        logger.info("来自客户端的消息:" + message);
    }

    /**
     * 发生错误时调用
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error){
        logger.info("发生错误");
        error.printStackTrace();
    }

    public void sendObject(Object o) throws IOException
    {
        try {
            this.session.getBasicRemote().sendText(JsonUtils.encode(o));
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    /**
     *  向指定client发送信息
     * @param id
     * @param o
     */
    public static void sendObjectToSomebody(String id,Object o) throws IOException
    {
        if(webSocketMap != null && webSocketMap.containsKey(id))
            webSocketMap.get(id).sendObject(o);
    }

    /**
     *  向所有的client发送相同的数据
     * @param o
     * @throws IOException
     */
    public static void sendObjectToAll(Object o) throws IOException
    {
        Iterator iter = webSocketMap.entrySet().iterator();
        while (iter.hasNext())
        {
            Map.Entry entry = (Map.Entry) iter.next();
            WebSocketService ser = (WebSocketService) entry.getValue();
            ser.sendObject(o);
        }
    }


    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketService.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketService.onlineCount--;
    }

}
